-- Copyright (c) 2011-2012 Casey Baxter
-- See LICENSE file for details

---------------------------------------------------------------------------------------------------
-- -= ObjectLayer =-
---------------------------------------------------------------------------------------------------
-- Setup
local PATH = (...):gsub("[\\/]", ""):match(".+%.") or ''

local love = love
local unpack = unpack
local pairs = pairs
local ipairs = ipairs
local Object = require(PATH .. "Object")
local ObjectLayer = {class = "ObjectLayer"}
ObjectLayer.__index = ObjectLayer

---------------------------------------------------------------------------------------------------
-- Creates and returns a new ObjectLayer
function ObjectLayer.init(o)
	return setmetatable(o, ObjectLayer)
end

---------------------------------------------------------------------------------------------------
-- Creates a new object, automatically inserts it into the layer, and then returns it
function ObjectLayer:newObject(o)
	local o = o or {}
	local nextid = map.nextObjectID
	local obj = Object.init{
		id       = nextid,
		name     = o.name or "",
		type     = o.type or "",
		x        = o.x or 0,
		y        = o.y or 0,
		width    = o.width  or 0,
		height   = o.height or 0,
		rotation = o.rotation or 0,
		gid      = o.gid,
		visible  = o.visible ~= 0,
	}
    self.objects[#self.objects+1] = obj
	map.nextObjectID = nextid + 1
    return obj
end

---------------------------------------------------------------------------------------------------
-- Sorting function for objects. We'll use this below in ObjectLayer:draw()
local function drawSort(o1, o2) 
    return o1.drawInfo.order < o2.drawInfo.order 
end

---------------------------------------------------------------------------------------------------
-- Draws the object layer. The way the objects are drawn depends on the map orientation and
-- if the object has an associated tile. It tries to draw the objects as closely to the way
-- Tiled does it as possible.
local di, dr, drawList, r, g, b, a, line, obj, offsetX, offsetY
local R, G, B, A
function ObjectLayer:draw()

    -- Early exit if the layer is not visible.
    if not self.visible then return end

    -- Exit if objects are not suppose to be drawn
    if not self.map.drawObjects then return end

    di = nil                            -- The draw info
    dr = {self.map:getDrawRange()}      -- The drawing range. [1-4] = x, y, width, height
    drawList = {}                       -- A list of the objects to be drawn
    r,g,b,a = love.graphics.getColor()    -- Save the color so we can set it back at the end
    
	if self.color then
		R, G, B, A = unpack(self.color)
	else
		R, G, B, A = 1, 1, 1, 1
	end
	A = self.opacity -- FIXME: correct behavior?
	
    line = love.graphics.getLineWidth() -- Save the line width too
    
    -- Put only objects that are on the screen in the draw list. If the screen range isn't defined
    -- add all objects
    for i = 1, #self.objects do
        obj = self.objects[i]
        obj:updateDrawInfo()
        di = obj.drawInfo
        if dr[1] and dr[2] and dr[3] and dr[4] then
            if  di.right > dr[1]-20 and 
                di.bottom > dr[2]-20 and 
                di.left < dr[1]+dr[3]+20 and 
                di.top < dr[2]+dr[4]+20 then 
                    drawList[#drawList+1] = obj
            end
        else
            drawList[#drawList+1] = obj
        end
    end
    
    -- Sort the draw list by the object's draw order
    table.sort(drawList, drawSort)

    -- Draw all the objects in the draw list.
    offsetX, offsetY = self.map.offsetX, self.map.offsetY
    for i = 1, #drawList do 
        obj = drawList[i]
        love.graphics.setColor(1,1,1,1)
        drawList[i]:draw(di.x, di.y, R, G, B, A)
    end
    
    -- Reset the color and line width
    love.graphics.setColor(r,b,g,a)
    love.graphics.setLineWidth(line)
end

---------------------------------------------------------------------------------------------------
-- Changes an object layer into a custom layer. A function can be passed to convert objects.
function ObjectLayer:toCustomLayer(convert)
    if convert then
        for i = 1, #self.objects do
            self.objects[i] = convert(self.objects[i])
        end
    end
    self.class = "CustomLayer"
    return setmetatable(self, nil)
end

---------------------------------------------------------------------------------------------------
-- Return the ObjectLayer class
return ObjectLayer
